package org.mwt.ws.business;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.xml.parsers.ParserConfigurationException;
import mwt.xml.xdbforms.dbms.XDBFManager;
import mwt.xml.xdbforms.dbms.exceptions.TypeNotFoundException;
import mwt.xml.xdbforms.dbms.metadata.MetadataManager;
import mwt.xml.xdbforms.dbms.metadata.impl.TableMetadata;
import mwt.xml.xdbforms.dbms.query.QueryManager;
import mwt.xml.xdbforms.xforms.XFormsModelManager;
import mwt.xml.xdbforms.xforms.XFormsUIManager;
import org.mwt.ws.business.exception.BusinessException;

public class XFormService {
    private static XFormService instance = null;
    private static XDBFManager xdbfm = null;

    public static synchronized void initInstance(XDBFManager xdbfm) {
        if (XFormService.instance != null) {
            throw new RuntimeException("Instance of XFormService already initialized!");
	}
        XFormService.instance = new XFormService(xdbfm);
    }

    public static synchronized XFormService getInstance() {
        if (XFormService.instance == null) {
            throw new RuntimeException("No instance of XFormService has been initialized!");
	}

        return XFormService.instance;
    }

    private XFormService(XDBFManager xdbfm) {
        XFormService.xdbfm = xdbfm;
    }

    private String getTableName(String sql) {
        Pattern pattern = Pattern.compile("table (if not exists )?([^(]+)", Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(sql);
        matcher.find();
        
        return matcher.group(2).trim();
    }

    private String loadFile(String fileName) throws FileNotFoundException, IOException {
        String fileStr = "";
        String line = "";

        FileReader fr = new FileReader(this.getClass().getResource("/org/mwt/ws/templates/"+fileName).getPath());
        BufferedReader bf = new BufferedReader(fr);

        while ((line = bf.readLine()) != null) {
            fileStr += line+"\n";
        }
        
        return fileStr;
    }

    public String createXForm(String dbName, String sql) throws BusinessException {
        String tableName = this.getTableName(sql);
        String xformsmodel;
        String xformsui;

        /*Pattern pattern = Pattern.compile("table (if not exists )?([^(]+)", Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(sql);
        matcher.find();
        tableName = matcher.group(2).trim();*/

        QueryManager qm = xdbfm.getQueryManager();
        MetadataManager mdm = xdbfm.getMetadataManager();
        XFormsModelManager xfmm = null;
        XFormsUIManager xfum = null;
        TableMetadata tmd = null;

        try {
            xfmm = xdbfm.getXFormsModelManager();
            xfum = xdbfm.getXFormsUIManager();
        } catch (ParserConfigurationException ex) {
            Logger.getLogger(XFormService.class.getName()).log(Level.SEVERE, null, ex);
            throw new BusinessException("Errore durante instanziazione manager del modello/UI XForms", ex);
        }

        try {
            qm.executeNonQuery("USE " + dbName);
            qm.executeNonQuery("DROP TABLE IF EXISTS "+tableName);
            qm.executeNonQuery(sql);
        } catch (SQLException ex) {
            Logger.getLogger(XFormService.class.getName()).log(Level.SEVERE, null, ex);
            throw new BusinessException("Errore durante la creazione della tabella temporanea "+dbName+"."+tableName, ex);
        }

        try {
            tmd = mdm.getTableMetadata(dbName, tableName);
        } catch (SQLException ex) {
            Logger.getLogger(XFormService.class.getName()).log(Level.SEVERE, null, ex);
            throw new BusinessException("Errore durante il recupero dei metadati della tabella temporanea "+dbName+"."+tableName, ex);
        }

        try {
            xformsmodel = xfmm.getModelAsString(tmd, "INSERT_HERE_YOUR_ACTION");
            xformsui = xfum.getUIAsString(tmd);
        } catch (TypeNotFoundException ex) {
            Logger.getLogger(XFormService.class.getName()).log(Level.SEVERE, null, ex);
            throw new BusinessException("Errore durante la creazione dell'xml XForms", ex);
        }

        try {
            qm.executeNonQuery("DROP TABLE IF EXISTS " + tableName);
        } catch (SQLException ex) {
            Logger.getLogger(XFormService.class.getName()).log(Level.SEVERE, null, ex);
            throw new BusinessException("Errore durante la cancellazione della tabella temporanea "+dbName+"."+tableName, ex);
        }

        return xformsmodel.concat(xformsui);
    }

    public String createInsertCode(String sql) throws BusinessException {
        String tablename = this.getTableName(sql);
        String template = "";

        try {
            template = this.loadFile("insertclass.tpl");
            template = template.replace("<tablename>", tablename);
        } catch (Exception ex) {
            Logger.getLogger(XFormService.class.getName()).log(Level.SEVERE, null, ex);
            throw new BusinessException("Errore durante la creazione del codice java per l'inserimento", ex);
        }

        return template;
    }

    public String createUpdateCode(String sql) throws BusinessException {
        String tablename = this.getTableName(sql);
        String template = "";

        try {
            template = this.loadFile("updateclass.tpl");
            template = template.replace("<tablename>", tablename);
        } catch (Exception ex) {
            Logger.getLogger(XFormService.class.getName()).log(Level.SEVERE, null, ex);
            throw new BusinessException("Errore durante la creazione del codice java per l'aggiornamento", ex);
        }

        return template;
    }
}
